<template>
    <el-upload
        ref="uploadFileRef"
        :limit="1"
        :on-exceed="handleExceed"
        :auto-upload="false"
        :on-change="changeFile"
        :show-file-list="false"
    >
        <template #trigger>
            <slot></slot>
        </template>
    </el-upload>
</template>

<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import { genFileId, ElMessage } from 'element-plus'
import type { UploadFile, UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
import useUserStore from '@/store/modules/user'
import useMessagesStore from '@/store/modules/messages'
import type { FileData } from '@/api/file/type'
import {
    determineFileType,
    calcFileSize,
    getImageDimensions,
    generateVideoThumbnail,
    determineFileImage,
} from '@/utils/chatfile'

// 用户仓库
const userStore = useUserStore()
// 消息仓库
const messageStore = useMessagesStore()
// 引用上传实例
const uploadFileRef = ref<UploadInstance | null>(null)
// 传递props
const props = defineProps({
    // 是否结束上传操作
    isEndUpload: { type: Boolean, required: true },
    // 上传文件的功能类型
    uploadType: { type: String, required: true },
})
// 用户选择的文件
const selectedFile = reactive<FileData>({
    fileType: '',
    fileData: null,
    fileName: '',
    fileSize: '',
    previewUrl: '',
    fileWidth: 0,
    fileHeight: 0,
})

// 处理文件
const reduceFile = async (uploadFile: UploadRawFile) => {
    //更新文件
    selectedFile.fileData = uploadFile
    //更新文件名
    selectedFile.fileName = uploadFile.name
    //文件字节大小
    const size = uploadFile.size
    if (size / 1024 / 1024 > 50) {
        return ElMessage.error('上传文件的大小不能超过50M')
    }

    //获取文件扩展名
    const ext = selectedFile.fileName.split('.').pop()?.toLowerCase()
    //根据后缀名判断文件类型
    selectedFile.fileType = determineFileType(ext as string)
    //更新文件URL为本地预览URL
    const previewFile = URL.createObjectURL(uploadFile)
    if (selectedFile.fileType === 'picture') {
        selectedFile.previewUrl = previewFile
        const imgimensions = await getImageDimensions(previewFile)
        selectedFile.fileWidth = imgimensions.width
        selectedFile.fileHeight = imgimensions.height
    }
    if (selectedFile.fileType === 'video') {
        try {
            //生成视频缩略图
            const previewImage = await generateVideoThumbnail(previewFile)
            selectedFile.previewUrl = previewImage.previewUrl
            selectedFile.fileWidth = previewImage.fileWidth
            selectedFile.fileHeight = previewImage.fileHeight
        } catch (error) {
            ElMessage.error('预览图加载失败')
        }
    }
    if (selectedFile.fileType === 'file') {
        //判定文件的具体类型，显示文件缩略图
        selectedFile.previewUrl = determineFileImage(ext as string)
    }

    //规范文件大小显示
    selectedFile.fileSize = calcFileSize(size)
    // 将最后文件的格式化内容传给父组件
    switch (props.uploadType) {
        case 'message':
            messageStore.selectedFile = selectedFile
            break
        case 'avatar':
            userStore.changeAvatar = selectedFile
            break
    }
}

//el-upload添加文件或更改文件时的钩子
const changeFile: UploadProps['onChange'] = async (uploadFile: UploadFile) => {
    if (uploadFile) {
        reduceFile(uploadFile.raw as UploadRawFile)
    }
}

//超出限制的文件处理函数
const handleExceed: UploadProps['onExceed'] = (files) => {
    uploadFileRef.value!.clearFiles()
    const file = files[0] as UploadRawFile
    file.uid = genFileId()
    uploadFileRef.value!.handleStart(file)
}

// 监听用户是否点击了取消上传
watch(
    () => props.isEndUpload,
    (newVal) => {
        if (newVal) {
            uploadFileRef.value!.clearFiles()
        }
    },
)
</script>

<style scoped lang="scss"></style>
